package tupelo
{
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.events.HTTPStatusEvent;
	import flash.events.IEventDispatcher;
	import flash.events.IOErrorEvent;
	import flash.events.ProgressEvent;
	import flash.events.SecurityErrorEvent;
	import flash.net.URLLoader;
	import flash.net.URLRequest;
	import flash.net.URLRequestMethod;
	import flash.net.URLVariables;
	
	import mx.managers.CursorManager;
	import mx.rpc.events.FaultEvent;
	import mx.rpc.events.ResultEvent;
	
	/**
	 * Dispatched when an TueploService call returns sucessfullly
	 * @eventType mx.rpc.events.ResultEvent
	 */
	[Event(name="result",type="mx.rpc.events.ResultEvent")]
	/**
	 * Dispatched when an TupeloService call fails
	 * @eventType mx.rpc.events.FaultEvent
	 */
	[Event(name="fault",type="mx.rpc.events.FaultEvent")]
	
	public class TupeloService extends EventDispatcher
	{
		public static const RESULT_FORMAT_RDF:String = "xml";
		
		public static const RESULT_FORMAT_NT:String = "nt";
		
		public static const RESULT_FORMAT_N3:String = "n3";
		
		public static const INPUT_FORMAT_RDF:String = "xml";
		
		public static const INPUT_FORMAT_NT:String = "nt";
		
		public static const INPUT_FORMAT_N3:String = "n3";
		
		public static const QUERY_SYNTAX_SPARQL:String = "sparql";
		
		private static const CONTENT_TYPE_TEXT:String = "text/plain";
		
		private static const CONTENT_TYPE_XML:String = "text/xml";
		
		private static const METHOD_TYPE_GET:String="GET";
		
		private static const METHOD_TYPE_PUT:String="PUT";
		
		private static const METHOD_TYPE_DELETE:String="DELETE";
		
		private static const METHOD_TYPE_MGET:String="MGET";
		
		private static const METHOD_TYPE_MPUT:String="MPUT";
		
		private static const METHOD_TYPE_MDELETE:String="MDELETE";
		
		private static const METHOD_TYPE_MQUERY:String="MQUERY";
		
		private static const METHOD_TYPE_POST:String="POST";
		
		private static const URI:String = "uri";
		
		private static const FORMAT:String="format";
		
		private static const DEPTH:String="depth";
		
		private static const SYNTAX:String="syntax";
		
		private static const RESULT:String="result";
		
		private static const METHOD:String="method";
		
		private static const FAULT:String="fault";
		
		private var _loader:URLLoader = new URLLoader();
		
		private var _url:String;
		
		private var _result:String;
		
		private var _default_method:String = "POST";
		
		public var showBusyCursor:Boolean;
		
		public function TupeloService(url:String="") 
		{
			configureListeners(_loader);
			_url = url;
			showBusyCursor = false;
		}
		
		private function createURLRequest(params:Object,data:Object=null):URLRequest
		{
			var result:URLRequest = new URLRequest();
			var url:String = _url;
			
			var urlVar:URLVariables = new URLVariables();
			for(var p:String in params)
				urlVar[p] = params[p];
				
			params = urlVar.toString();
			if( params && params != "" )
			{
	             url += (url.indexOf("?") > -1) ? '&' : '?';
	             url += params;
			}
			
			result.data = data + " ";
			result.url = url;
			result.contentType = CONTENT_TYPE_TEXT;
			result.method = URLRequestMethod.POST;
			return result;
		}
		
		private function clearResult():void
		{
			_result = null; 	
		}
		// ----------------------
		//	Properties
		//
		// ----------------------
		
		[Bindable("resultForBinding")]
		
		public function get lastResult():String
		{
			return _result;
		}
		
		private function internalSend(params:Object,data:Object=null):void
		{
			if(showBusyCursor)
				CursorManager.setBusyCursor();
				
			var urlRequest:URLRequest = createURLRequest(params,data);
			trace(" uriRequest method " + urlRequest.method);
			_loader.load(urlRequest);
		}
		
		public function mGet(uri:String,depth:int,format:String=RESULT_FORMAT_RDF):void
		{
			var par:Object = new Object();
			par[URI] = uri;
			par[DEPTH] = depth;
			par[FORMAT] = format;
			par[METHOD] = METHOD_TYPE_MGET;
			
			internalSend(par);
		}
		public function mPut(triples:String,uri:String,format:String=RESULT_FORMAT_RDF):void
		{
			var par:Object = new Object();
			par[FORMAT] = format;
			par[METHOD] = METHOD_TYPE_MPUT;
			par[URI] = uri;
			
			internalSend(par,triples);
		}
		public function mDelete(triples:String,format:String=RESULT_FORMAT_RDF):void
		{
			var par:Object = new Object();
			par[FORMAT] = format;
			par[METHOD] = METHOD_TYPE_MDELETE;
			
			internalSend(par,triples);
		}
		public function mQuery(query:String,syntax:String=QUERY_SYNTAX_SPARQL,format:String=RESULT_FORMAT_RDF):void
		{
			var par:Object = new Object();
			par[SYNTAX] = syntax;
			par[FORMAT] = format;
			par[METHOD] = METHOD_TYPE_MQUERY;

			internalSend(par,query);
		}
		public function tPut(data:String,uri:String):void
		{
			var par:Object = new Object();
			par[URI] = uri;
			
			internalSend(par,data);
		}
		public function tGet(uri:String):void
		{
			var par:Object = new Object();
			par[URI] = uri;
			
			internalSend(par);
		}
		public function tDelete(uri:String):void
		{
			var par:Object = new Object();
			par[URI] = uri;
			
			internalSend(par);
		}
		 
        private function configureListeners(dispatcher:IEventDispatcher):void {
            dispatcher.addEventListener(Event.COMPLETE, completeHandler);
            dispatcher.addEventListener(Event.OPEN, openHandler);
            dispatcher.addEventListener(ProgressEvent.PROGRESS, progressHandler);
            dispatcher.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
            dispatcher.addEventListener(HTTPStatusEvent.HTTP_STATUS, httpStatusHandler);
            dispatcher.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandler);
        }
        private function preHandler(event:Event):void
        {
   	       	if(showBusyCursor)
        		CursorManager.removeBusyCursor();
 
        }
        private function completeHandler(event:Event):void {
			
			preHandler(event);
			        	
            var loader:URLLoader = URLLoader(event.target);
            
            _result = loader.data;
            
            trace(" Result " + _result);
            
            var revent:ResultEvent = new ResultEvent(RESULT,false,false,_result);
            dispatchEvent(revent);
        }

        private function openHandler(event:Event):void {
            trace("openHandler: " + event);
        }
        private function progressHandler(event:ProgressEvent):void {
            trace("progressHandler loaded:" + event.bytesLoaded + " total: " + event.bytesTotal);
        }

        private function securityErrorHandler(event:SecurityErrorEvent):void {
            preHandler(event);
        }

        private function httpStatusHandler(event:HTTPStatusEvent):void {
            trace("httpStatusHandler: " + event);
        }

        private function ioErrorHandler(event:IOErrorEvent):void {
			preHandler(event); 
           var revent:FaultEvent = new FaultEvent(FAULT);
        }
        
        public function set url(url:String):void
        {
        	_url = url;
        }

	}
}